#include <sdk.h>
#include "M_Code_StyledTextCtrl.h"
#include "ThreadSearch.h"
#include "ThreadSearchView.h"
#include "ThreadSearchConfPanel.h"
#include "ThreadSearchControlIds.h"
#include "logging.h"

namespace {
  PluginRegistrant<ThreadSearch> reg( _T( "ThreadSearch" ) );
}

int idEditUndo = XRCID( "idEditUndo" );
int idEditRedo = XRCID( "idEditRedo" );
int idEditCopy = XRCID( "idEditCopy" );
int idEditCut = XRCID( "idEditCut" );
int idEditPaste = XRCID( "idEditPaste" );
int idEditSwapHeaderSource = XRCID( "idEditSwapHeaderSource" );
int idEditGotoMatchingBrace = XRCID( "idEditGotoMatchingBrace" );
int idEditBookmarks = XRCID( "idEditBookmarks" );
int idEditBookmarksToggle = XRCID( "idEditBookmarksToggle" );
int idEditBookmarksPrevious = XRCID( "idEditBookmarksPrevious" );
int idEditBookmarksNext = XRCID( "idEditBookmarksNext" );
int idEditFoldAll = XRCID( "idEditFoldAll" );
int idEditUnfoldAll = XRCID( "idEditUnfoldAll" );
int idEditToggleAllFolds = XRCID( "idEditToggleAllFolds" );
int idEditFoldBlock = XRCID( "idEditFoldBlock" );
int idEditUnfoldBlock = XRCID( "idEditUnfoldBlock" );
int idEditToggleFoldBlock = XRCID( "idEditToggleFoldBlock" );
int idEditEOLCRLF = XRCID( "idEditEOLCRLF" );
int idEditEOLCR = XRCID( "idEditEOLCR" );
int idEditEOLLF = XRCID( "idEditEOLLF" );
int idEditEncoding = XRCID( "idEditEncoding" );
int idEditSelectAll = XRCID( "idEditSelectAll" );
int idEditCommentSelected = XRCID( "idEditCommentSelected" );
int idEditUncommentSelected = XRCID( "idEditUncommentSelected" );
int idEditToggleCommentSelected = XRCID( "idEditToggleCommentSelected" );
int idEditAutoComplete = XRCID( "idEditAutoComplete" );
int idMenuEditCopy = XRCID( "idEditCopy" );
int idMenuEditPaste = XRCID( "idEditPaste" );

BEGIN_EVENT_TABLE( ThreadSearch, M_Code_Plugin )
  EVT_UPDATE_UI( controlIDs.Get( ControlIDs::idMenuViewThreadSearch ), ThreadSearch::OnMnuViewThreadSearchUpdateUI )
  EVT_MENU( controlIDs.Get( ControlIDs::idMenuViewThreadSearch ), ThreadSearch::OnMnuViewThreadSearch )
  EVT_UPDATE_UI( controlIDs.Get( ControlIDs::idMenuViewFocusThreadSearch ), ThreadSearch::OnMnuViewFocusThreadSearchUpdateUI )
  EVT_MENU( controlIDs.Get( ControlIDs::idMenuViewFocusThreadSearch ), ThreadSearch::OnMnuViewFocusThreadSearch )
  EVT_UPDATE_UI( controlIDs.Get( ControlIDs::idMenuSearchThreadSearch ), ThreadSearch::OnMnuSearchThreadSearchUpdateUI )
  EVT_MENU( controlIDs.Get( ControlIDs::idMenuSearchThreadSearch ), ThreadSearch::OnMnuSearchThreadSearch )
  EVT_MENU( controlIDs.Get( ControlIDs::idMenuCtxThreadSearch ), ThreadSearch::OnCtxThreadSearch )
  EVT_MENU( idMenuEditCopy, ThreadSearch::OnMnuEditCopy )
  EVT_UPDATE_UI( idMenuEditCopy, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_MENU( idMenuEditPaste, ThreadSearch::OnMnuEditPaste )
  EVT_TOOL( controlIDs.Get( ControlIDs::idBtnOptions ), ThreadSearch::OnBtnOptionsClick )
  EVT_TOOL( controlIDs.Get( ControlIDs::idBtnSearch ), ThreadSearch::OnBtnSearchClick )
  EVT_TEXT_ENTER( controlIDs.Get( ControlIDs::idCboSearchExpr ), ThreadSearch::OnCboSearchExprEnter )
  EVT_TEXT( controlIDs.Get( ControlIDs::idCboSearchExpr ), ThreadSearch::OnCboSearchExprEnter )
  EVT_TEXT_ENTER( controlIDs.Get( ControlIDs::idSearchDirPath ), ThreadSearch::OnCboSearchExprEnter )
  EVT_TEXT_ENTER( controlIDs.Get( ControlIDs::idSearchMask ), ThreadSearch::OnCboSearchExprEnter )
  EVT_UPDATE_UI( idEditUndo, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditRedo, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditCopy, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditCut, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditPaste, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditSwapHeaderSource, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditGotoMatchingBrace, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditFoldAll, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditUnfoldAll, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditToggleAllFolds, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditFoldBlock, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditUnfoldBlock, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditToggleFoldBlock, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditEOLCRLF, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditEOLCR, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditEOLLF, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditEncoding, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditSelectAll, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditBookmarksToggle, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditBookmarksNext, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditBookmarksPrevious, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditCommentSelected, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditAutoComplete, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditUncommentSelected, ThreadSearch::OnMnuEditCopyUpdateUI )
  EVT_UPDATE_UI( idEditToggleCommentSelected, ThreadSearch::OnMnuEditCopyUpdateUI )
END_EVENT_TABLE()

ThreadSearch::ThreadSearch()
  : m_SearchedWord( wxEmptyString ),
    m_pThreadSearchView( NULL ),
    m_pViewManager( NULL ),
    m_CtxMenuIntegration( true ),
    m_UseDefValsForThreadSearch( true ),
    m_ShowSearchControls( true ),
    m_ShowDirControls( false ),
    m_ShowCodePreview( true ),
    m_DeletePreviousResults( true ),
    m_LoggerType( ThreadSearchLoggerBase::TypeList ),
    m_DisplayLogHeaders( true ),
    m_DrawLogLines( false ),
    m_AutosizeLogColumns( false ),
    m_pCboSearchExpr( 0 ),
    m_SplitterMode( wxSPLIT_VERTICAL ),
    m_FileSorting( InsertIndexManager::SortByFilePath ) {
  if( !Manager::LoadResource( _T( "ThreadSearch.zip" ) ) ) {
    NotifyMissingFile( _T( "ThreadSearch.zip" ) );
  }
}

ThreadSearch::~ThreadSearch() {
}

void ThreadSearch::OnAttach() {
  bool showPanel;
  int  sashPosition;
  ThreadSearchViewManagerBase::eManagerTypes mgrType;
  wxArrayString searchPatterns, searchDirs, searchMasks;
  LoadConfig( showPanel, sashPosition, mgrType, searchPatterns, searchDirs, searchMasks );
  m_pThreadSearchView = new ThreadSearchView( *this );
  m_pThreadSearchView->SetSearchHistory( searchPatterns, searchDirs, searchMasks );
  m_pViewManager = ThreadSearchViewManagerBase::BuildThreadSearchViewManagerBase( m_pThreadSearchView, true, mgrType );
  m_pViewManager->ShowView( showPanel );
  int x, y;
  m_pThreadSearchView->GetSize( &x, &y );
  m_pThreadSearchView->SetSashPosition( x / 2 );
  m_pThreadSearchView->Update();
  if( sashPosition != 0 ) {
    m_pThreadSearchView->SetSashPosition( sashPosition );
  }
  m_pThreadSearchView->ShowSearchControls( m_ShowSearchControls );
  m_OnReleased = false;
}

void ThreadSearch::OnRelease( bool ) {
  if( m_OnReleased ) {
    return;
  }
  m_OnReleased = true;
  if( m_pThreadSearchView != 0 ) {
    m_pViewManager->RemoveViewFromManager();
    m_pThreadSearchView->Destroy();
  }
  delete m_pViewManager;
  m_pViewManager = 0;
}

void ThreadSearch::OnThreadSearchViewDestruction() {
  m_pThreadSearchView->ApplySplitterSettings( m_ShowCodePreview, m_SplitterMode );
  SaveConfig( m_pViewManager->IsViewShown(),
              m_pThreadSearchView->GetSashPosition(),
              m_pViewManager->GetManagerType(),
              m_pThreadSearchView->GetSearchHistory(),
              m_pThreadSearchView->GetSearchDirsHistory(),
              m_pThreadSearchView->GetSearchMasksHistory() );
  m_pThreadSearchView = NULL;
}

void ThreadSearch::BuildMenu( wxMenuBar* menuBar ) {
  size_t i;
  int idx = menuBar->FindMenu( _T( "视图(&V)" ) );
  if( idx != wxNOT_FOUND ) {
    wxMenu* menu = menuBar->GetMenu( idx );
    wxMenuItemList& items = menu->GetMenuItems();
    for( i = 0; i < items.GetCount(); ++i ) {
      if( items[i]->IsSeparator() ) {
        menu->InsertCheckItem( i, controlIDs.Get( ControlIDs::idMenuViewThreadSearch ), _T( "Thread search" ) );
        break;
      }
    }
    if( i == items.GetCount() ) {
      menu->AppendCheckItem( controlIDs.Get( ControlIDs::idMenuViewThreadSearch ), _T( "Thread search" ) );
    }
    menu->Append( controlIDs.Get( ControlIDs::idMenuViewFocusThreadSearch ), _T( "Focus Thread Search" ) );
  }
  idx = menuBar->FindMenu( _T( "查找(&R)" ) );
  if( idx != wxNOT_FOUND ) {
    wxMenu* menu = menuBar->GetMenu( idx );
    wxMenuItemList& items = menu->GetMenuItems();
    for( i = 0; i < items.GetCount(); ++i ) {
      if( items[i]->IsSeparator() ) {
        menu->Insert( i, controlIDs.Get( ControlIDs::idMenuSearchThreadSearch ), _T( "搜索" ) );
        break;
      }
    }
    if( i == items.GetCount() ) {
      menu->Append( controlIDs.Get( ControlIDs::idMenuSearchThreadSearch ), _T( "搜索" ) );
    }
  }
}

void ThreadSearch::OnMnuViewThreadSearch( wxCommandEvent& event ) {
  if( !IsAttached() ) {
    return;
  }
  m_pViewManager->ShowView( event.IsChecked() );
}

void ThreadSearch::OnMnuSearchThreadSearch( wxCommandEvent& ) {
  if( !IsAttached() ) {
    return;
  }
  if( ( GetCursorWord( m_SearchedWord ) == true ) && ( m_SearchedWord.IsEmpty() == false ) ) {
    RunThreadSearch( m_SearchedWord, true );
  } else {
    m_pViewManager->ShowView( true );
  }
}

void ThreadSearch::OnMnuViewFocusThreadSearch( wxCommandEvent& ) {
  if( !IsAttached() ) {
    return;
  }
  GetCursorWord( m_SearchedWord );
  m_pViewManager->ShowView( true );
  m_pViewManager->Raise();
  m_pThreadSearchView->FocusSearchCombo( m_SearchedWord );
}

void ThreadSearch::OnCtxThreadSearch( wxCommandEvent& ) {
  if( !IsAttached() ) {
    return;
  }
  RunThreadSearch( m_SearchedWord, true );
}

void ThreadSearch::OnMnuViewThreadSearchUpdateUI( wxUpdateUIEvent& ) {
  if( !IsAttached() ) {
    return;
  }
  wxMenuBar *menubar = Manager::Get()->GetAppFrame()->GetMenuBar();
  menubar->Check( controlIDs.Get( ControlIDs::idMenuViewThreadSearch ), m_pViewManager->IsViewShown() );
}

void ThreadSearch::OnMnuSearchThreadSearchUpdateUI( wxUpdateUIEvent& event ) {
  if( !IsAttached() ) {
    return;
  }
  event.Enable( m_pThreadSearchView->IsSearchRunning() == false );
}

void ThreadSearch::OnMnuViewFocusThreadSearchUpdateUI( wxUpdateUIEvent& event ) {
  if( !IsAttached() ) {
    return;
  }
  event.Enable( m_pThreadSearchView->IsSearchRunning() == false );
}

void ThreadSearch::BuildModuleMenu( const ModuleType type, wxMenu* pMenu, const FileTreeData* ) {
  wxMenuItem* pMenuItem = NULL;
  wxString tmp1, sText, msg;
  if( !pMenu || !IsAttached() ) {
    return;
  }
  if( ( type == mtEditorManager ) && ( m_CtxMenuIntegration == true ) ) {
    if( GetCursorWord( m_SearchedWord ) == true ) {
      tmp1 = m_SearchedWord;
      if( m_SearchedWord.Len() > 10 ) {
        tmp1.Remove( 0, tmp1.length() - 3 );
        msg = F( _T( "%4.4s...%s" ), m_SearchedWord.wx_str(), tmp1.wx_str() );
      } else {
        msg << m_SearchedWord.wx_str();
      }
      sText = _T( "查找文本: ' " ) + msg + _T( " '" );
      pMenuItem = pMenu->Insert( 0, controlIDs.Get( ControlIDs::idMenuCtxThreadSearch ), sText );
      pMenuItem->Enable( !m_pThreadSearchView->IsSearchRunning() );
    }
  }
}

int ThreadSearch::GetInsertionMenuIndex( const wxMenu* const pCtxMenu ) {
  if( !IsAttached() ) {
    return -1;
  }
  const wxMenuItemList ItemsList = pCtxMenu->GetMenuItems();
  for( int i = 0; i < ( int )ItemsList.GetCount(); ++i ) {
    if( ItemsList[i]->GetLabel().StartsWith( _T( "查找文本:" ) ) ) {
      return ++i;
    }
  }
  return -1;
}

cbConfigurationPanel* ThreadSearch::GetConfigurationPanel( wxWindow* parent ) {
  if( !IsAttached() ) {
    return NULL;
  }
  return new ThreadSearchConfPanel( *this, parent );
}


void ThreadSearch::Notify() {
  if( !IsAttached() ) {
    return;
  }
  m_pThreadSearchView->Update();
  SaveConfig( m_pViewManager->IsViewShown(), m_pThreadSearchView->GetSashPosition(),
              m_pViewManager->GetManagerType(), m_pThreadSearchView->GetSearchHistory(),
              m_pThreadSearchView->GetSearchDirsHistory(), m_pThreadSearchView->GetSearchMasksHistory() );
}


void ThreadSearch::LoadConfig( bool& showPanel, int& sashPosition, ThreadSearchViewManagerBase::eManagerTypes& mgrType,
                               wxArrayString& searchPatterns, wxArrayString& searchDirs, wxArrayString& searchMasks ) {
  if( !IsAttached() ) {
    return;
  }
  ConfigManager* pCfg = Manager::Get()->GetConfigManager( _T( "ThreadSearch" ) );
  m_FindData.SetMatchWord( pCfg->ReadBool( _T( "/MatchWord" ), true ) );
  m_FindData.SetStartWord( pCfg->ReadBool( _T( "/StartWord" ), false ) );
  m_FindData.SetMatchCase( pCfg->ReadBool( _T( "/MatchCase" ), true ) );
  m_FindData.SetRegEx( pCfg->ReadBool( _T( "/RegEx" ), false ) );
  m_FindData.SetHiddenSearch( pCfg->ReadBool( _T( "/HiddenSearch" ), true ) );
  m_FindData.SetRecursiveSearch( pCfg->ReadBool( _T( "/RecursiveSearch" ), true ) );
  m_CtxMenuIntegration = pCfg->ReadBool( _T( "/CtxMenuIntegration" ), true );
  m_UseDefValsForThreadSearch  = pCfg->ReadBool( _T( "/UseDefaultValues" ), true );
  m_ShowSearchControls = pCfg->ReadBool( _T( "/ShowSearchControls" ), true );
  m_ShowDirControls = pCfg->ReadBool( _T( "/ShowDirControls" ), false );
  m_ShowCodePreview = pCfg->ReadBool( _T( "/ShowCodePreview" ), false );
  m_DeletePreviousResults = pCfg->ReadBool( _T( "/DeletePreviousResults" ), false );
  m_DisplayLogHeaders = pCfg->ReadBool( _T( "/DisplayLogHeaders" ), true );
  m_DrawLogLines = pCfg->ReadBool( _T( "/DrawLogLines" ), false );
  m_AutosizeLogColumns = pCfg->ReadBool( _T( "/AutosizeLogColumns" ), true );
  showPanel = pCfg->ReadBool( _T( "/ShowPanel" ), true );
  m_FindData.SetScope( pCfg->ReadInt( _T( "/Scope" ), ScopeProjectFiles ) );
  m_FindData.SetSearchPath( pCfg->Read( _T( "/DirPath" ), wxEmptyString ) );
  m_FindData.SetSearchMask( pCfg->Read( _T( "/Mask" ), _T( "*.cpp;*.c;*.h" ) ) );
  sashPosition = pCfg->ReadInt( _T( "/SplitterPosn" ), 0 );
  int splitterMode = pCfg->ReadInt( _T( "/SplitterMode" ), wxSPLIT_VERTICAL );
  m_SplitterMode = wxSPLIT_VERTICAL;
  if( splitterMode == wxSPLIT_HORIZONTAL ) {
    m_SplitterMode = wxSPLIT_HORIZONTAL;
  }
  int managerType = pCfg->ReadInt( _T( "/ViewManagerType" ), ThreadSearchViewManagerBase::TypeMessagesNotebook );
  mgrType = ThreadSearchViewManagerBase::TypeMessagesNotebook;
  if( managerType == ThreadSearchViewManagerBase::TypeLayout ) {
    mgrType = ThreadSearchViewManagerBase::TypeLayout;
  }
  int loggerType = pCfg->ReadInt( _T( "/LoggerType" ), ThreadSearchLoggerBase::TypeList );
  m_LoggerType = ThreadSearchLoggerBase::TypeList;
  if( loggerType == ThreadSearchLoggerBase::TypeTree ) {
    m_LoggerType = ThreadSearchLoggerBase::TypeTree;
  }
  searchPatterns = pCfg->ReadArrayString( _T( "/SearchPatterns" ) );
  searchDirs = pCfg->ReadArrayString( _T( "/SearchDirs" ) );
  if( searchDirs.empty() ) {
    searchDirs.push_back( m_FindData.GetSearchPath() );
  }
  searchMasks = pCfg->ReadArrayString( _T( "/SearchMasks" ) );
  if( searchMasks.empty() ) {
    searchMasks.push_back( m_FindData.GetSearchMask() );
  }
}

void ThreadSearch::SaveConfig( bool showPanel, int sashPosition, ThreadSearchViewManagerBase::eManagerTypes,
                               const wxArrayString& searchPatterns, const wxArrayString& searchDirs,
                               const wxArrayString& searchMasks ) {
  ConfigManager* pCfg = Manager::Get()->GetConfigManager( _T( "ThreadSearch" ) );
  pCfg->Write( _T( "/MatchWord" ), m_FindData.GetMatchWord() );
  pCfg->Write( _T( "/StartWord" ), m_FindData.GetStartWord() );
  pCfg->Write( _T( "/MatchCase" ), m_FindData.GetMatchCase() );
  pCfg->Write( _T( "/RegEx" ), m_FindData.GetRegEx() );
  pCfg->Write( _T( "/HiddenSearch" ), m_FindData.GetHiddenSearch() );
  pCfg->Write( _T( "/RecursiveSearch" ), m_FindData.GetRecursiveSearch() );
  pCfg->Write( _T( "/CtxMenuIntegration" ), m_CtxMenuIntegration );
  pCfg->Write( _T( "/UseDefaultValues" ), m_UseDefValsForThreadSearch );
  pCfg->Write( _T( "/ShowSearchControls" ), m_ShowSearchControls );
  pCfg->Write( _T( "/ShowDirControls" ), m_ShowDirControls );
  pCfg->Write( _T( "/ShowCodePreview" ), m_ShowCodePreview );
  pCfg->Write( _T( "/DeletePreviousResults" ), m_DeletePreviousResults );
  pCfg->Write( _T( "/DisplayLogHeaders" ), m_DisplayLogHeaders );
  pCfg->Write( _T( "/DrawLogLines" ), m_DrawLogLines );
  pCfg->Write( _T( "/AutosizeLogColumns" ), m_AutosizeLogColumns );
  pCfg->Write( _T( "/ShowPanel" ), showPanel );
  pCfg->Write( _T( "/Scope" ), m_FindData.GetScope() );
  pCfg->Write( _T( "/DirPath" ), m_FindData.GetSearchPath() );
  pCfg->Write( _T( "/Mask" ), m_FindData.GetSearchMask() );
  pCfg->Write( _T( "/SplitterPosn" ), sashPosition );
  pCfg->Write( _T( "/SplitterMode" ), ( int )m_SplitterMode );
  pCfg->Write( _T( "/ViewManagerType" ), m_pViewManager->GetManagerType() );
  pCfg->Write( _T( "/LoggerType" ), m_LoggerType );
  pCfg->Write( _T( "/FileSorting" ), m_FileSorting );
  pCfg->Write( _T( "/SearchPatterns" ), searchPatterns );
  pCfg->Write( _T( "/SearchDirs" ), searchDirs );
  pCfg->Write( _T( "/SearchMasks" ), searchMasks );
}

void ThreadSearch::OnBtnOptionsClick( wxCommandEvent &event ) {
  if( !IsAttached() ) {
    return;
  }
  m_pThreadSearchView->OnBtnOptionsClick( event );
}

void ThreadSearch::OnBtnSearchClick( wxCommandEvent &event ) {
  if( !IsAttached() ) {
    return;
  }
  if( m_pThreadSearchView->IsSearchRunning() ) {
    m_pThreadSearchView->OnBtnSearchClick( event );
  }
}

void ThreadSearch::RunThreadSearch( const wxString& text, bool isCtxSearch ) {
  if( !IsAttached() ) {
    return;
  }
  ThreadSearchFindData findData = m_FindData;
  if( ( isCtxSearch == true ) && ( m_UseDefValsForThreadSearch == true ) ) {
    findData.SetMatchCase( true );
    findData.SetMatchWord( true );
    findData.SetStartWord( false );
    findData.SetRegEx( false );
  }
  findData.SetFindText( text );
  m_pViewManager->ShowView( true );
  m_pThreadSearchView->ThreadedSearch( findData );
}

void ThreadSearch::OnCboSearchExprEnter( wxCommandEvent &event ) {
  if( !IsAttached() ) {
    return;
  }
}

bool ThreadSearch::GetCursorWord( wxString& sWord ) {
  bool wordFound = false;
  M_Code_Editor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor();
  M_Code_StyledTextCtrl* control = ed->GetControl();
  int pos = control->GetCurrentPos();
  int ws  = control->WordStartPosition( pos, true );
  int we  = control->WordEndPosition( pos, true );
  const wxString word = control->GetTextRange( ws, we );
  sWord = wxEmptyString;
  if( ed != NULL ) {
    sWord = control->GetSelectedText();
    if( sWord != wxEmptyString ) {
      sWord.Trim( true );
      sWord.Trim( false );
      wxString::size_type pos = sWord.find( _T( '\n' ) );
      if( pos != wxString::npos ) {
        sWord.Remove( pos, sWord.length() - pos );
        sWord.Trim( true );
        sWord.Trim( false );
      }
      return !sWord.IsEmpty();
    }
    if( !word.IsEmpty() ) {
      sWord.Clear();
      while( --ws > 0 ) {
        const wxChar ch = control->GetCharAt( ws );
        if( ch <= _T( ' ' ) ) {
          continue;
        } else if( ch == _T( '~' ) ) {
          sWord << _T( "~" );
        }
        break;
      }
      sWord << word;
      wordFound = true;
    }
  }
  return wordFound;
}

void ThreadSearch::OnMnuEditCopy( wxCommandEvent& event ) {
  if( !IsAttached() ) {
    event.Skip();
    return;
  }
  wxWindow* pFocused = wxWindow::FindFocus();
  if( pFocused == m_pCboSearchExpr ) {
    if( m_pCboSearchExpr->CanCopy() ) {
      m_pCboSearchExpr->Copy();
    }
    LOGIT( _T( "OnMnuEditcopy for m_pCboSearchExpr" ) );
  } else if( pFocused == m_pThreadSearchView->m_pCboSearchExpr ) {
    if( m_pThreadSearchView->m_pCboSearchExpr->CanCopy() ) {
      m_pThreadSearchView->m_pCboSearchExpr->Copy();
    }
    LOGIT( _T( "OnMnuEditcopy for m_pThreadSearchView->m_pCboSearchExpr" ) );
  } else if( pFocused == static_cast<wxWindow*>( m_pThreadSearchView->m_pSearchPreview ) ) {
    bool hasSel = m_pThreadSearchView->m_pSearchPreview->GetSelectionStart() != m_pThreadSearchView->m_pSearchPreview->GetSelectionEnd();
    if( hasSel ) {
      m_pThreadSearchView->m_pSearchPreview->Copy();
    }
    LOGIT( _T( "OnMnuEditcopy for m_pSearchPreview" ) );
  } else {
    event.Skip();
  }
  return;
}

void ThreadSearch::OnMnuEditCopyUpdateUI( wxUpdateUIEvent& event ) {
  bool hasSel = false;
  if( !IsAttached() ) {
    event.Skip();
    return;
  }
  wxWindow* pFocused = wxWindow::FindFocus();
  if( not pFocused ) {
    return;
  }
  wxMenuBar* mbar = Manager::Get()->GetAppFrame()->GetMenuBar();
  if( not mbar ) {
    return;
  }
  if( pFocused == m_pCboSearchExpr ) {
    hasSel =  m_pCboSearchExpr->CanCopy() ;
  } else if( pFocused == m_pThreadSearchView->m_pCboSearchExpr ) {
    hasSel = m_pThreadSearchView->m_pCboSearchExpr->CanCopy();
  } else if( pFocused == static_cast<wxWindow*>( m_pThreadSearchView->m_pSearchPreview ) ) {
    hasSel = m_pThreadSearchView->m_pSearchPreview->GetSelectionStart() != m_pThreadSearchView->m_pSearchPreview->GetSelectionEnd();
  }
  if( hasSel ) {
    mbar->Enable( idMenuEditCopy, hasSel );
    wxToolBar* pMainToolBar = ( wxToolBar* ) ::wxFindWindowByName( _T( "toolbar" ), NULL );
    if( pMainToolBar ) {
      pMainToolBar->EnableTool( idMenuEditCopy, hasSel );
    }
    return;
  }
  event.Skip();
  return;
}

void ThreadSearch::OnMnuEditPaste( wxCommandEvent& event ) {
  wxWindow* pFocused = wxWindow::FindFocus();
  wxString focusedStr = pFocused->GetName();
  if( !IsAttached() ) {
    event.Skip();
    return;
  }
  if( not m_IsAttached ) {
    event.Skip();
    return;
  }
  if( not pFocused ) {
    event.Skip();
    return;
  }
  if( ( pFocused == m_pThreadSearchView->m_pSearchPreview ) || ( pFocused == ( wxWindow* )m_pThreadSearchView->m_pLogger ) ) {
    return;
  }
  if( ( pFocused != m_pCboSearchExpr ) && ( pFocused != m_pThreadSearchView->m_pCboSearchExpr ) ) {
    event.Skip();
    return;
  }
  if( pFocused == m_pCboSearchExpr ) {
    m_pCboSearchExpr->Paste();
  }
  if( pFocused == m_pThreadSearchView->m_pCboSearchExpr ) {
    m_pThreadSearchView->m_pCboSearchExpr->Paste();
  }
  return;
}

void ThreadSearch::SetManagerType( ThreadSearchViewManagerBase::eManagerTypes mgrType ) {
  if( mgrType != m_pViewManager->GetManagerType() ) {
    bool show( true );
    if( m_pViewManager != NULL ) {
      show = m_pViewManager->IsViewShown();
      m_pViewManager->RemoveViewFromManager();
      delete m_pViewManager;
    }
    m_pViewManager = ThreadSearchViewManagerBase::BuildThreadSearchViewManagerBase( m_pThreadSearchView, true, mgrType );
    m_pViewManager->ShowView( show );
  }
}
